#!/usr/bin/env bash

# Bash completion for Deno Version Manager
# Copyright (C) 2020 ~ 2025, Chen Su and all contributors.

if ! type dvm &> /dev/null
then
  return
fi

# Add available aliases to the auto-completion options list.
_dvm_add_aliases_to_opts() {
  if [ ! -d "$DVM_DIR/aliases" ]
  then
    return
  fi

  if [ -z "$(ls -A "$DVM_DIR/aliases")" ]
  then
    return 0
  fi

  for path in "$DVM_DIR/aliases"/*
  do
    alias_name=${path##*/}
    version=$(cat "$path")

    if [ -f "$DVM_DIR/versions/$version/deno" ]
    then
      opts="$opts $alias_name"
    fi
  done
}

# Add commands and top-level options (--help and --version) to the options list.
_dvm_add_command_and_top_option() {
  if [[ ${cur} == -* ]]
  then
    opts="-h --help --version"
  else
    opts="alias clean current deactivate doctor help install list list-remote
      ls ls-remote run upgrade unalias uninstall use which"
  fi
}

# Add the specified options to the options list if none have been input yet.
_dvm_add_exclusive_option() {
  if _dvm_no_option_input "${@}"
  then
    opts="$opts $*"
  fi
}

# Add options for the install command.
_dvm_add_install_option() {
  _dvm_add_exclusive_option "--from-binary" "--from-source"
  _dvm_add_options "--registry=" "--skip-validation" "--skip-download-cache"
  _dvm_add_options "--sha256sum" "--no-sha256sum"
}

# Add the specified options to the options list.
_dvm_add_options() {
  for opt in "${@}"
  do
    if ! [[ ${COMP_WORDS[*]} =~ $opt ]]
    then
      opts="$opts $opt"
    fi
  done
}

# Add common options to the auto-completion options list.
_dvm_add_options_to_opts() {
  local prev

  prev="$1"

  if [ "$prev" == "run" ]
  then
    return
  fi

  if [[ ${cur} != -* ]]
  then
    return
  fi

  _dvm_add_exclusive_option "-q" "--quiet"
  _dvm_add_exclusive_option "--color" "--no-color"
  _dvm_add_options "--verbose"
}

# Add available installed versions to the auto-completion options list.
_dvm_add_versions_to_opts() {
  if [ ! -d "$DVM_DIR/versions" ]
  then
    return
  fi

  if [ -z "$(ls -A "$DVM_DIR/versions")" ]
  then
    return 0
  fi

  for path in "$DVM_DIR/versions"/*
  do
    if [ -f "$path/deno" ]
    then
      version=${path##*/}

      opts="$opts $version"
    fi
  done
}

# Set auto-completion for a specific command.
_dvm_completion() {
  local command
  local cur

  COMPREPLY=()
  cur="${COMP_WORDS[COMP_CWORD]}"

  if [ "$COMP_CWORD" = "1" ]
  then
    _dvm_add_command_and_top_option
  else
    command="${COMP_WORDS[1]}"

    case "$command" in
    "doctor")
      _dvm_add_exclusive_option "--fix"
      ;;
    "install")
      if [[ ${cur} == -* ]]
      then
        _dvm_add_install_option
      fi
      ;;
    "use"|"uninstall"|"which")
      if ! _dvm_has_non_option_parameter  "$cur"
      then
        if [ "$command" = "which" ] && _dvm_has_active_version
        then
          opts="current"
        fi

        _dvm_add_versions_to_opts
        _dvm_add_aliases_to_opts
      fi
      ;;
    "run")
      if _dvm_has_non_option_parameter "$cur"
      then
        COMPREPLY=( "$(compgen -W "${opts}" -- "${cur}")" )
        return
      fi

      _dvm_add_versions_to_opts
      _dvm_add_aliases_to_opts
      ;;
    "unalias")
      if [ "$COMP_CWORD" == "2" ] || ! _dvm_has_non_option_parameter "$cur"
      then
        _dvm_add_aliases_to_opts
      fi
      ;;
    *)
      opts=""
      ;;
    esac

    _dvm_add_options_to_opts "$prev"
  fi

  COMPREPLY=( "$(compgen -W "${opts}" -- "${cur}")" )
}

# Check if any Deno version installed by DVM is currently active.
_dvm_has_active_version() {
  echo "$PATH" | grep -q "$DVM_DIR/versions"
}

# Check whether the parameter list contains any non-option parameters.
_dvm_has_non_option_parameter() {
  local cur
  cur="$1"

  for word in "${COMP_WORDS[@]:2}"
  do
    if [ "$word" == "" ] || [ "$word" == "$cur" ]
    then
      continue
    fi

    if [[ "$word" != -* ]]
    then
      true
      return
    fi
  done

  false
}

# Check whether the specified options have been input.
_dvm_no_option_input() {
  for opt in "${@}"
  do
    if [[ ${COMP_WORDS[*]} =~ $opt ]]
    then
      false
      return
    fi
  done

  true
}

if [ -n "$ZSH_NAME" ]
then
  autoload -U +X compinit && compinit
  autoload -U +X bashcompinit && bashcompinit
fi

complete -F _dvm_completion dvm
